//***************************************************************************
//   Copyright(c)2020, Xidian University D405.
//           All rights reserved
//
//   File name       :   txfifo2axis.v
//   Module name     :   txfifo2axis
//   Author          :   Zhao Yuchen
//   Date            :   2022/05/21
//   Version         :   v1.0, wzk add async module
//                       v1.1, zyc line:193 tx_fifo_top -> tx_fifo_top_10g
//                       v1.2, update txfifo_start cross clk domain method.
//   Edited by       :   Zhao Yuchen
//***************************************************************************
//`define VCS_MODEL
module txfifo2axis_10g #
(
    parameter MAC_DWIDTH = 64  , // MAC Data Width
    parameter MAC_KWIDTH = 8   , // MAC Keep Width
    parameter MAC_KBITS  = 3   , // MAC Keep Bits
    parameter MAC_UWIDTH = 4   , // MAC User Width
    parameter DMA_DWIDTH = 128 , // DMA Data Width
    parameter MEM_AWIDTH = 10  , // MEM Addr Width
    parameter LEN_DWIDTH = 11  , // LEN Data Width
    parameter LEN_AWIDTH = 10    // LEN Addr Width
)
(
    input  wire  wclk,
    input  wire  rclk,
    input  wire  rstn_rclk,
    input  wire  rstn_wclk,
    
    input  wire  start_i,
    //Write
    input  wire                    wr_data_en_i    ,
    input  wire                    wr_leng_en_i    ,
    input  wire [DMA_DWIDTH-1 : 0] wr_data_i       ,
    input  wire [LEN_DWIDTH-1 : 0] wr_leng_i       ,
    output wire                    wr_full_o       ,
    
    
    output wire                    m_axis_tvalid_o ,
    output wire                    m_axis_tlast_o  ,
    output wire [MAC_KWIDTH-1 : 0] m_axis_tkeep_o  ,
    output wire [MAC_DWIDTH-1 : 0] m_axis_tdata_o  ,
    input                          m_axis_tready_i ,
    output wire [MAC_UWIDTH-1 : 0] m_axis_tuser_o  ,
    input  wire [11:0]             ram_dp_cfg_register
);

    /*
    //======================================================================================================
    // RSTN CDC
    reg rstn_wclk_sync0 ;
    reg rstn_wclk_sync1 ;
    reg rstn_rclk_sync0 ;
    reg rstn_rclk_sync1 ;

    always @( posedge wclk or negedge arstn ) begin
        if ( !arstn ) begin
            rstn_wclk_sync0 <= 1'b0 ;
            rstn_wclk_sync1 <= 1'b0 ;
        end
        else begin
            rstn_wclk_sync0 <= 1'b1 ;
            rstn_wclk_sync1 <= rstn_wclk_sync0 ;
        end
    end

    always @( posedge rclk or negedge arstn ) begin
        if ( !arstn ) begin
            rstn_rclk_sync0 <= 1'b0 ;
            rstn_rclk_sync1 <= 1'b0 ;
        end
        else begin
            rstn_rclk_sync0 <= 1'b1 ;
            rstn_rclk_sync1 <= rstn_rclk_sync0 ;
        end
    end
    */
    //======================================================================================================
    wire [LEN_DWIDTH-1 : 0] rd_leng;
    wire leng_fifo_empty;
    wire data_fifo_full;
    wire leng_fifo_full;
    assign wr_full_o = data_fifo_full | leng_fifo_full;

    reg[1 : 0] txfifo_state;
    reg[1 : 0] txfifo_next_state;
    reg[1 : 0] txfifo_state_r;

    localparam S_IDLE = 2'b01;
    localparam S_SEND = 2'b10;

    wire txfifo_start;
    assign txfifo_start = (txfifo_state == S_SEND) && (txfifo_state_r == S_IDLE);

    /*** 0521 txfifo_state cross clk domain, modify by zyc begin ***/

    //reg[5 : 0] txfifo_start_ff;
    //wire txfifo_start_5x;
    //assign txfifo_start_5x = |txfifo_start_ff[5:1];
    reg[LEN_AWIDTH : 0]  transaction_cnt;

    always @( posedge wclk or negedge rstn_wclk )
    begin
        if(!rstn_wclk)
        begin
            txfifo_state_r <= 'd0;
        end
        else
        begin
            txfifo_state_r     <= txfifo_state;
        end
    end

    wire txfifo_start_clk_dma;
    wire txfifo_start_clk_mac;

    assign txfifo_start_clk_dma = txfifo_start;
    reg txfifo_start_q1, txfifo_start_q2, txfifo_start_q3, txfifo_start_q4;
    always @(posedge wclk or negedge rstn_wclk )
    begin
        if(~rstn_wclk)
            txfifo_start_q1 <= 1'b0;
        else
            txfifo_start_q1 <= txfifo_start_q1 ^ txfifo_start_clk_dma;
    end

    always @(posedge rclk or negedge rstn_rclk)
    begin
        if(~rstn_rclk)
        begin
            txfifo_start_q2 <= 1'b0;
            txfifo_start_q3 <= 1'b0;
            txfifo_start_q4 <= 1'b0;
        end
        else
        begin
            txfifo_start_q2 <= txfifo_start_q1;
            txfifo_start_q3 <= txfifo_start_q2;
            txfifo_start_q4 <= txfifo_start_q3;
        end
    end

    assign txfifo_start_clk_mac = txfifo_start_q3 ^ txfifo_start_q4;

    /*** 0521 txfifo_state cross clk domain, modify by zyc end ***/

    /*** 0619 begin ***/

    reg txfifo_start_clk_mac_ff1;
    reg txfifo_start_clk_mac_ff2;

    always @(posedge rclk or negedge rstn_rclk)
    begin
        if(~rstn_rclk)
        begin
            txfifo_start_clk_mac_ff1 <= 1'b0;
            txfifo_start_clk_mac_ff2 <= 1'b0;
        end
        else
        begin
            txfifo_start_clk_mac_ff1 <= txfifo_start_clk_mac;
            txfifo_start_clk_mac_ff2 <= txfifo_start_clk_mac_ff1;
        end
    end

    /**** 0619 end ***/

    always @( posedge wclk or negedge rstn_wclk )
    begin
        if(!rstn_wclk)
            transaction_cnt <= 'd0;
        else if(start_i && txfifo_start)
            transaction_cnt <= transaction_cnt;
        else if(start_i)
            transaction_cnt <= transaction_cnt + 'd1;
        else if(txfifo_start)
            transaction_cnt <= transaction_cnt - 'd1;
        else
            transaction_cnt <= transaction_cnt;
    end

    wire send_done;
    reg  send_done_ff1;
    reg  send_done_ff2;
    reg  send_done_clr;
    
    always @( posedge wclk or negedge rstn_wclk )
    begin
        if(!rstn_wclk)
        begin  
            send_done_ff1 <= 1'b0;
            send_done_ff2 <= 1'b0;
        end
        else
        begin
            send_done_ff1 <= send_done;
            send_done_ff2 <= send_done_ff1;
        end
    end

    always @( posedge wclk or negedge rstn_wclk )
    begin
        if(!rstn_wclk)
            send_done_clr <= 1'b0;
        else if(send_done_ff2)
            send_done_clr <= 1'b1;
        else
            send_done_clr <= 1'b0;
    end

    always @( posedge wclk or negedge rstn_wclk )
    begin
        if(!rstn_wclk)
            txfifo_state <= S_IDLE;
        else
            txfifo_state <= txfifo_next_state;
    end

    always @(*)
    begin
        case(txfifo_state)
            S_IDLE :
                if((transaction_cnt != 'd0) && (send_done_ff2 == 1'b0))
                    txfifo_next_state = S_SEND;
                else
                    txfifo_next_state = S_IDLE;
            S_SEND :
                if(send_done_ff2 == 1'b1)
                    txfifo_next_state = S_IDLE;
                else
                    txfifo_next_state = S_SEND;
            default:
                txfifo_next_state = S_IDLE;
        endcase
    end

    //======================================================================================================
`ifdef VCS_MODEL
    native_fifo_2T #( .DW(LEN_DWIDTH), .AW(LEN_AWIDTH) ) 
    len_fifo
    (
        .wclk          ( wclk            ),
        .wr_rstn       ( rstn_wclk       ),
        .rclk          ( rclk            ),
        .rd_rstn       ( rstn_rclk       ),

        .wr_en_i       ( wr_leng_en_i    ),
        .wr_din_i      ( wr_leng_i       ),
        .full_o        ( leng_fifo_full  ),
        
        .rd_en_i       ( txfifo_start_clk_mac ),
        .rd_dout_o     ( rd_leng              ),
        .empty_o       ( leng_fifo_empty ) 
    );
    tx_fifo_top_10g #
    (
        .MAC_DWIDTH     (MAC_DWIDTH),
        .MAC_KWIDTH     (MAC_KWIDTH),
        .MAC_KBITS      (MAC_KBITS ),
        .MAC_UWIDTH     (MAC_UWIDTH),
        .DMA_DWIDTH     (DMA_DWIDTH),
        .MEM_AWIDTH     (MEM_AWIDTH),
        .LEN_DWIDTH     (LEN_DWIDTH),
        .LEN_AWIDTH     (LEN_AWIDTH)
    )
    data_fifo
    (
        .clkr              (rclk),
        .clkw              (wclk),
        //.np_sys_rst_n      (rstn_rclk_sync1),
        .rstn_rclk         (rstn_rclk),
        .rstn_wclk         (rstn_wclk),
        .axi_ttready_i     (m_axis_tready_i),
        .axi_ttvalid_o     (m_axis_tvalid_o),
        .axi_ttlast_o      (m_axis_tlast_o ),
        .axi_ttkeep_o      (m_axis_tkeep_o ),
        .axi_ttdata_o      (m_axis_tdata_o ),
        .axi_ttuser_o      (m_axis_tuser_o ),
        
        .start_send_e_i    (txfifo_start_clk_mac_ff2),
        .send_done_o       (send_done),
        .send_done_clr_i   (send_done_clr),

        .frame_len_i       (rd_leng      ),
                         
        .wr_tx_fifo_e_i    (wr_data_en_i   ), 
        .wr_tx_fifo_data_i (wr_data_i      ), 
        .tx_fifo_full_o    (data_fifo_full )
    );
`else
    async_fifo_d512_w11 len_fifo_tx_10g
    (
        .wclk          ( wclk            ),
        .wr_rstn       ( rstn_wclk       ),
        .rclk          ( rclk            ),
        .rd_rstn       ( rstn_rclk       ),

        .wr_en_i       ( wr_leng_en_i    ),
        .wr_din_i      ( wr_leng_i       ),
        .full_o        ( leng_fifo_full  ),
        
        .rd_en_i       ( txfifo_start_clk_mac ),
        .rd_dout_o     ( rd_leng              ),
        .empty_o       ( leng_fifo_empty ),
        .ram_dp_cfg_register    (ram_dp_cfg_register)
    );
    
    tx_fifo_top_10g data_fifo_tx_10g
    (
        .clkr              (rclk),
        .clkw              (wclk),
        .rstn_rclk         (rstn_rclk),
        .rstn_wclk         (rstn_wclk),
        .axi_ttready_i     (m_axis_tready_i),
        .axi_ttvalid_o     (m_axis_tvalid_o),
        .axi_ttlast_o      (m_axis_tlast_o ),
        .axi_ttkeep_o      (m_axis_tkeep_o ),
        .axi_ttdata_o      (m_axis_tdata_o ),
        .axi_ttuser_o      (m_axis_tuser_o ),
        
        .start_send_e_i    (txfifo_start_clk_mac_ff2),
        .send_done_o       (send_done),
        .send_done_clr_i   (send_done_clr),

        .frame_len_i       (rd_leng      ),
                         
        .wr_tx_fifo_e_i    (wr_data_en_i   ), 
        .wr_tx_fifo_data_i (wr_data_i      ), 
        .tx_fifo_full_o    (data_fifo_full ),
        .ram_dp_cfg_register    (ram_dp_cfg_register)
    );
`endif

    
endmodule
